package org.system.core.service.system;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.system.core.annotation.DataScope;
import org.system.core.common.Constants;
import org.system.core.domain.entity.*;
import org.system.core.exception.ServiceException;
import org.system.core.mapper.system.*;
import org.system.core.utils.MessageUtils;
import org.system.core.utils.SecurityUtils;
import org.system.core.utils.StringUtils;
import org.system.core.utils.spring.SpringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author baoRoot
 */
@Service
public class SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysPostService sysPostService;

    @Autowired
    private SysUserPostMapper sysUserPostMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    public SysUser selectUserByUserName(String userName) {
        return sysUserMapper.selectUserByUserName(userName);
    };

    public boolean updateUserAvatar(String userName, String avatar) {
        return sysUserMapper.updateUserAvatar(userName, avatar) > 0;
    }

    public boolean checkUserNameUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = sysUserMapper.checkUserNameUnique(user.getUserName());
        return StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue();
    }

    public boolean registerUser(SysUser user) {
        return sysUserMapper.insertUser(user) > 0;
    }

    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectUserList(SysUser user) {
        return sysUserMapper.selectUserList(user);
    }

    public int resetPassword(String userName, String password) {
        return sysUserMapper.resetPassword(userName, password);
    }

    public int updateUserProfile(SysUser user) {
        return sysUserMapper.updateUser(user);
    }

    public void checkUserDataScope(Long userId) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            SysUser user = new SysUser();
            user.setUserId(userId);
            List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);
            if (StringUtils.isEmpty(users)) {
                throw new ServiceException(MessageUtils.message("system.user.no_permission"));
            }
        }
    }

    public Map<String, Object> selectUserInfo(Long userId) {
        if(userId == null || userId <= 0) {
            throw new ServiceException(MessageUtils.message("system.user.no_id"));
        }
        checkUserDataScope(userId);
        List<SysRole> roles = sysRoleService.selectRoleAll();
        HashMap<String, Object> map = new HashMap<>();
        map.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        map.put("posts", sysPostService.selectPostAll());
        SysUser user = sysUserMapper.selectUserById(userId);
        user.setPassword("");
        map.put("user", user);
        map.put("postIds", sysPostService.selectPostListByUserId(userId));
        map.put("roleIds", user.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
        return map;
    }

    public boolean checkPhoneUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = sysUserMapper.checkPhoneUnique(user.getPhonenumber());
        return StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue();
    }

    public boolean checkEmailUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = sysUserMapper.checkEmailUnique(user.getEmail());
        return StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue();
    }

    public boolean checkDeptStatus(Long deptId) {
        SysDept sysDept = sysDeptMapper.selectDeptById(deptId);
        if (sysDept == null) {
            throw new ServiceException(MessageUtils.message("system.user.dept_not"));
        }
        return Constants.DEPT_DISABLE.equals(sysDept.getStatus());
    };

    @Transactional
    public void insertUser(SysUser user) {
        checkUserUnique(user);
        user.setCreateBy(SecurityUtils.getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        if(sysUserMapper.insertUser(user) <= 0) {
            throw new ServiceException(MessageUtils.message("system.user.add_user"));
        }
        insertUserPost(user);
        insertUserRole(user);
    }

    @DataScope(deptAlias = "d")
    public List<SysDept> selectDeptList(SysDept dept) {
        return sysDeptMapper.selectDeptList(dept);
    }

    public void checkDeptDataScope(Long deptId) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId()) && StringUtils.isNotNull(deptId)) {
            SysDept dept = new SysDept();
            dept.setDeptId(deptId);
            List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
            if (StringUtils.isEmpty(depts)) {
                throw new ServiceException("没有权限访问部门数据！");
            }
        }
    }

    @DataScope(deptAlias = "d")
    public List<SysRole> selectRoleList(SysRole role) {
        return sysRoleMapper.selectRoleList(role);
    }

    public void checkRoleDataScope(Long... roleIds) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            for (Long roleId : roleIds) {
                SysRole role = new SysRole();
                role.setRoleId(roleId);
                List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
                if (StringUtils.isEmpty(roles)) {
                    throw new ServiceException("没有权限访问角色数据！");
                }
            }
        }
    }

    @Transactional
    public void updateUser(SysUser user) {
        checkUserAllowed(user);
        checkUserDataScope(user.getUserId());
        checkDeptDataScope(user.getDeptId());
        checkRoleDataScope(user.getRoleIds());
        checkUserUnique(user);
        user.setCreateBy(SecurityUtils.getUsername());
        Long userId = user.getUserId();
        sysUserRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(user);
        sysUserPostMapper.deleteUserPostByUserId(userId);
        insertUserPost(user);
        if (sysUserMapper.updateUser(user) <= 0) {
            throw new ServiceException(MessageUtils.message("system.user.update_user"));
        }
    }

    public void checkUserUnique(SysUser user) {
        if(checkUserNameUnique(user)){
            throw new ServiceException(MessageUtils.message("system.user.user_account"));
        }
        if(StringUtils.isNotEmpty(user.getPhonenumber()) && checkPhoneUnique(user)) {
            throw new ServiceException(MessageUtils.message("system.user.phone_exist"));
        }
        if (StringUtils.isNotEmpty(user.getEmail()) && checkEmailUnique(user)) {
            throw new ServiceException(MessageUtils.message("system.user.email_exist"));
        }
        if (user.getDeptId() != null && checkDeptStatus(user.getDeptId())) {
            throw new ServiceException(MessageUtils.message("system.user.dept_error"));
        }
    }

    public void insertUserRole(SysUser user) {
        this.insertUserRole(user.getUserId(), user.getRoleIds());
    }

    public void insertUserRole(Long userId, Long[] roleIds) {
        if (StringUtils.isNotEmpty(roleIds)) {
            // 新增用户与角色管理
            List<SysUserRole> list = new ArrayList<>(roleIds.length);
            for (Long roleId : roleIds) {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            sysUserRoleMapper.batchUserRole(list);
        }
    }

    public void insertUserPost(SysUser user) {
        Long[] posts = user.getPostIds();
        if (StringUtils.isNotEmpty(posts)) {
            // 新增用户与岗位管理
            List<SysUserPost> list = new ArrayList<>(posts.length);
            for (Long postId : posts) {
                SysUserPost up = new SysUserPost();
                up.setUserId(user.getUserId());
                up.setPostId(postId);
                list.add(up);
            }
            sysUserPostMapper.batchUserPost(list);
        }
    }

    public void checkUserAllowed(SysUser user){
        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
            throw new ServiceException(MessageUtils.message("system.user.administrator"));
        }
    }

    @Transactional
    public void deleteUser(Long[] userIds) {
        if(ArrayUtils.contains(userIds, SecurityUtils.getUserId())) {
            throw new ServiceException(MessageUtils.message("system.user.no_delete"));
        }
        for(Long userId : userIds) {
            checkUserAllowed(new SysUser(userId));
            checkUserDataScope(userId);
        }
        sysUserRoleMapper.deleteUserRole(userIds);
        sysUserPostMapper.deleteUserPost(userIds);
        if (sysUserMapper.deleteUserByIds(userIds) <=0 ) {
            throw new ServiceException(MessageUtils.message("system.user.delete_fail"));
        }
    }

    public void resetUserPassword(SysUser sysUser){
        checkUserAllowed(sysUser);
        checkUserDataScope(sysUser.getUserId());
        sysUser.setPassword(SecurityUtils.encryptPassword(sysUser.getPassword()));
        sysUser.setUpdateBy(SecurityUtils.getUsername());
        if (sysUserMapper.updateUser(sysUser) <= 0) {
            throw new ServiceException(MessageUtils.message("system.user.reset_password"));
        }
    }

    public void changeStatus(SysUser sysUser){
        checkUserAllowed(sysUser);
        checkUserDataScope(sysUser.getUserId());
        sysUser.setUpdateBy(SecurityUtils.getUsername());
        if (sysUserMapper.updateUser(sysUser) <= 0){
            throw new ServiceException(MessageUtils.message("system.user.edit_status_fail"));
        }
    }

    public SysUser selectUserById(Long userId) {
        return sysUserMapper.selectUserById(userId);
    }

    @Transactional
    public void insertUserAuth(Long userId, Long[] roleIds){
        if(userId == null) {
            throw new ServiceException(MessageUtils.message("system.user.no_id"));
        }
        checkUserDataScope(userId);
        sysUserRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(userId, roleIds);
    }

    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectAllocatedList(SysUser user) {
        return sysUserMapper.selectAllocatedList(user);
    }

    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectUnallocatedList(SysUser user) {
        return sysUserMapper.selectUnallocatedList(user);
    }

}
